/*
 * $Id: pcf50606.c,v 1.1 2008/03/17 08:02:32 zhulin Exp $
 */
#include "config.h"
#include "types.h"
#include "util.h"
#include "bulverde.h"
#include "udelay.h"

#define DEBUG_PCF50606 1

#define CKEN		__REG( CLK_BASE_PHYSICAL + CKEN_OFFSET )
#define PWIDBR		__REG( PWR_BASE_PHYSICAL + PIDBR_OFFSET )
#define PWICR		__REG( PWR_BASE_PHYSICAL + PI2CR_OFFSET )
#define PWISR		__REG( PWR_BASE_PHYSICAL + PISR_OFFSET )
#define PWISAR		__REG( PWR_BASE_PHYSICAL + PISAR_OFFSET )
#define PCFR		__REG( PWR_BASE_PHYSICAL + PCFR_OFFSET )

#if 0
#define GPDR0		__REG( GPIO_BASE_PHYSICAL + GPDR0_OFFSET )
#define GAFR0_L		__REG( GPIO_BASE_PHYSICAL + GAFR0_L_OFFSET )
#define GFER0		__REG( GPIO_BASE_PHYSICAL + GFER0_OFFSET )
#define ICMR		__REG( INTC_BASE_PHYSICAL + ICMR_OFFSET )
#endif

#define CKEN15_PI2C		(1<<15)

#define ICR_START		(1<<0)
#define ICR_STOP		(1<<1)
#define ICR_ACKNAK		(1<<2)
#define ICR_TB			(1<<3)
#define ICR_SCLE		(1<<5)
#define ICR_IUE			(1<<6)
#define ICR_ALDIE		(1<<12)
#define ICR_MA			(1<<4)
#define ICR_UR			(1<<14)

#define ISR_ITE			(1<<6)
#define ISR_IRF			(1<<7)

#define PCF50606_IIC_AD		(0x10)

#define PCF50606_ID			(0x00)
#define PCF50606_OOCS   	( 0x01 )
#define PCF50606_INT1		( 0x02 )
#define PCF50606_INT2		( 0x03 )
#define PCF50606_INT3		( 0x04 )
#define PCF50606_INT1M		( 0x05 )
#define PCF50606_INT2M		( 0x06 )
#define PCF50606_INT3M		( 0x07 )
#define PCF50606_OOCC1	 	( 0x08 )
#define PCF50606_OOCC2   	( 0x09 )
#define PCF50606_PSSC		( 0x18 )
#define PCF50606_PWROKM		( 0x19 )
#define PCF50606_DCDC1		( 0x1B )
#define PCF50606_DCDC2		( 0x1C )
#define PCF50606_DCDC4		( 0x1E )
#define PCF50606_DCDEC1		( 0x1F )
#define PCF50606_DCUDC1		( 0x21 )
#define PCF50606_IOREGC		( 0x23 )
#define PCF50606_D1REGC1	( 0x24 )
#define PCF50606_D2REGC1	( 0x25 )
#define PCF50606_D3REGC1	( 0x26 )
#define PCF50606_LPREGC1	( 0x27 )
#define PCF50606_LPREGC2	( 0x28 )
#define PCF50606_MBCC1          ( 0x29 )
#define PCF50606_MBCC2          ( 0x2A )
#define PCF50606_MBCC3		( 0x2B )
#define PCF50606_BBCC		( 0x2D )
#define PMIC_REG_DCUD_50	( 0x1A )
#define PMIC_REG_LDO_25		( 0x10 )
#define PCF50606_BVMC		( 0x34 )
#define PCF50606_GPOC1		( 0x38 )
#define PCF50606_GPOC2		( 0x39 )
#define PCF50606_GPOC3		( 0x3A )



#define	ZEROS	0
#define BIT0	0x00000001
#define BIT1	0x00000002
#define BIT2	0x00000004
#define BIT3	0x00000008
#define BIT4	0x00000010
#define BIT5	0x00000020
#define BIT6	0x00000040
#define BIT7	0x00000080
/**********************************************************************/
/* OPMOD */
#define PMIC_OPMOD0   ZEROS
#define PMIC_OPMOD1   (               BIT5  )
#define PMIC_OPMOD2   (        BIT6         )
#define PMIC_OPMOD3   (        BIT6 | BIT5  )
#define PMIC_OPMOD4   ( BIT7                )
#define PMIC_OPMOD5   ( BIT7        | BIT5  )
#define PMIC_OPMOD6   ( BIT7 | BIT6         )
#define PMIC_OPMOD7   ( BIT7 | BIT6 | BIT5  )


static int _pcf50606_initialized = 0;
static char devid = PCF50606_IIC_AD;
static int iic_timeout = 0x100000;

static char readD1REGvalue(void);
static char readD2REGvalue(void);
static char readD3REGvalue(void);
static char readIOREGvalue(void);
static char readLPREGvalue(void);
static char readDCDEvalue(void);
static char readDCDvalue(void);
static char readDCUDvalue(void);
static void writeD1REGvalue(char value);
static void writeD3REGvalue(char value);
static void writeDCUDvalue(char value);
static void writeDCDvalue( char value );

static char readPCFregister( char address );

#define I2C_PWICR_INIT    (ICR_SCLE | (1 << 15))
#define I2C_PWISR_INIT	0x7ff
//Bill
extern volatile int iimageupdate_by_usb;

void pcf50606_Interrupt_Processing();

static void emu_iic_delay(int us)
{
	int i;
	int va = 0;

	for(i = 0; i < us * 1400; i++)
	{
		va++;
	}
	return;
}

void i2c_pcf5060x_workaround()
{
	int i;

	GAFR0_L &= ~(0x3c0);
	GPSR0 = (1 << 3);
	GPDR0 &= ~(1 << 4);		//SDA
	GPDR0 |= (1 << 3);		//SCL

	for(i = 0; i < 10; i++)
	{
		emu_iic_delay(1);
		GPCR0 = (1 << 3);
		emu_iic_delay(1);
		GPSR0 = (1 << 3);
	}

	return;
}

static char readPCFregister( char address ) 	// busy waiting
{
	int i;
	/* simon */
	char value;

	/* simon, see Table 9-5 */

	/* 1. START<target slave address><write> : master-transmitter*/
	/* device id */
	// PIDBR: Power Manager I2C Data Buffer Register
	// 0x40f0_018B
	PWIDBR = devid & 0xFE;
	// PICR
	// 0x40f0_0190
	PWICR |= ICR_START;				/* SEND a START pulse */
	PWICR &= ~(ICR_STOP);			/* do not send a STOP */
	PWICR &= ~(ICR_ALDIE);			/* Arbitration Loss Detected Interrupt Enable */
	PWICR |= ICR_TB;				/* Transfer a Byte */

#ifdef DEBUG_PCF50606
//	printk( "PCF50606: %s(%d) START<deviceid><write>\n", __FUNCTION__, __LINE__ );
#endif

	/* simon, do we need to wait for ISR_ITE after writing target slave address? */
#if 1
	// PISR: Power Manager I2C Slave Address Register
	// 0x40F0_01A0
	// check for IDBR Transmit Empty
	i = 0;
	while (!(PWISR & ISR_ITE) && (i++ < iic_timeout));
	PWISR |= ISR_ITE;
#endif

	/* 2. Initiate first data byte transfer */
	/* register address */
	PWIDBR = address;
	PWICR &= ~(ICR_START);
	PWICR &= ~(ICR_STOP);
	PWICR &= ~(ICR_ALDIE);
	PWICR |= ICR_TB;

#ifdef DEBUG_PCF50606
//	printk( "PCF50606: %s(%d) <data=address:%x>\n", __FUNCTION__, __LINE__, address );
#endif
	i = 0;
	while (!(PWISR & ISR_ITE) && (i++ < iic_timeout));
	PWISR |= ISR_ITE;

	/* device id again? */
	PWIDBR = devid | 0x01;
	PWICR |= ICR_START;
	PWICR &= ~(ICR_STOP);
	PWICR &= ~(ICR_ALDIE);
	PWICR |= ICR_TB;

#ifdef DEBUG_PCF50606
//	printk( "PCF50606: %s(%d) START<deviceid=%x><read>\n", __FUNCTION__, __LINE__, devid );
#endif
	i = 0;
	while (!(PWISR & ISR_ITE) && (i++ < iic_timeout));
	PWISR |= ISR_ITE;

	PWICR &= ~(ICR_START);
	PWICR |= ICR_STOP;
	PWICR &= ~(ICR_ALDIE);
	PWICR |= ICR_ACKNAK;
	PWICR |= ICR_TB;

#ifdef DEBUG_PCF50606
//	printk( "PCF50606: %s(%d) <data><NAK>STOP\n", __FUNCTION__, __LINE__ );
#endif
	i = 0;
	// PISR: Power Manager I2C Slave Address Register
	// 0x40F0_01A0
	// check for IDBR Receive Full
	while (!(PWISR & ISR_IRF) && (i++ < iic_timeout));
	PWISR |= ISR_IRF;
	/* simon */
	value = PWIDBR;

	PWICR &= ~(ICR_STOP);
	PWICR &= ~(ICR_ACKNAK);

#ifdef DEBUG_PCF50606
//	printk("%s(%d) %02x %02x \n", __FUNCTION__, __LINE__, address, value );
#endif
	return value;
}


static void writePCFregister( char address, char data ) 	// busy waiting
{
	int i;
#ifdef DEBUG_PCF50606
//	printk("%s %02x %02x \n", __FUNCTION__, address, data );
#endif

	PWIDBR = devid & 0xFE;
	PWICR |= ICR_START;
	PWICR &= ~(ICR_STOP);
	PWICR &= ~(ICR_ALDIE);
	PWICR |= ICR_TB;

	i = 0;
	while (!(PWISR & ISR_ITE) && (i++ < iic_timeout));
	PWISR |= ISR_ITE;

	PWIDBR = address;
	PWICR &= ~(ICR_START);
	PWICR &= ~(ICR_STOP);
	PWICR &= ~(ICR_ALDIE);
	PWICR |= ICR_TB;

	i = 0;
	while (!(PWISR & ISR_ITE) && (i++ < iic_timeout));
	PWISR |= ISR_ITE;

	PWIDBR = data;
	PWICR &= ~(ICR_START);
	PWICR |= ICR_STOP;
	PWICR &= ~(ICR_ALDIE);
	PWICR |= ICR_TB;

	i = 0;
	while (!(PWISR & ISR_ITE) && (i++ < iic_timeout));
	PWISR |= ISR_ITE;

	PWICR &= ~(ICR_STOP);
	return;
}




typedef struct parvol {
	char 	par;
	char	vol;
} parvol_t;

static parvol_t	D123parvol[] =
{
	{ 0x00,  9 }, { 0x01, 10 }, { 0x02, 11 }, { 0x03, 12 },
	{ 0x04, 13 }, { 0x05, 14 }, { 0x06, 15 }, { 0x07, 16 },
	{ 0x08, 17 }, { 0x09, 18 }, { 0x0a, 19 }, { 0x0b, 20 },
	{ 0x0c, 21 }, { 0x0d, 22 }, { 0x0e, 23 }, { 0x0f, 24 },
	{ 0x10, 25 }, { 0x11, 26 }, { 0x12, 27 }, { 0x13, 28 },
	{ 0x14, 29 }, { 0x15, 30 }, { 0x16, 31 }, { 0x17, 32 },
	{ 0x18, 33 }, { 0xFF, 00 }
};


static char readD1REGvalue(void)
{
	char value, param;
	int i;

	value = readPCFregister( PCF50606_D1REGC1 );
	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x001F;

	for ( i = 0 ; D123parvol[i].par != 0xFF ; i++ ) {
		if ( param == D123parvol[i].par ) {
			return D123parvol[i].vol;
		}
	}
	return 0;
}

static void writeD1REGvalue(char value)
{
	int i;

	for ( i = 0 ; D123parvol[i].par != 0xFF ; i++ ) {
		if ( value == D123parvol[i].vol ) {
			writePCFregister( PCF50606_D1REGC1 , D123parvol[i].par | PMIC_OPMOD7 );
			return;
		}
	}
	// write 0 value , disable power controller
	writePCFregister( PCF50606_D1REGC1 , PMIC_OPMOD0 );
	return;
}

static char readD2REGvalue(void)
{
	char value, param;
	int i;

	value = readPCFregister( PCF50606_D2REGC1 );
	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x001F;

	for ( i = 0 ; D123parvol[i].par != 0xFF ; i++ ) {
		if ( param == D123parvol[i].par ) {
			return D123parvol[i].vol;
		}
	}
	return 0;
}

static char readD3REGvalue(void)
{
	char value, param;
	int i;

	value = readPCFregister( PCF50606_D3REGC1 );
	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x001F;

	for ( i = 0 ; D123parvol[i].par != 0xFF ; i++ ) {
		if ( param == D123parvol[i].par ) {
			return D123parvol[i].vol;
		}
	}
	return 0;
}

static void writeD3REGvalue(char value)
{
	int i;

	for ( i = 0 ; D123parvol[i].par != 0xFF ; i++ ) {
		if ( value == D123parvol[i].vol ) {
			writePCFregister( PCF50606_D3REGC1 , D123parvol[i].par | PMIC_OPMOD7 );
			return;
		}
	}
	// write 0 value , disable power controller
	writePCFregister( PCF50606_D3REGC1 , PMIC_OPMOD0 );
	return;
}

static parvol_t	IOparvol[] =
{
	{ 0x09, 18 }, { 0x0a, 19 }, { 0x0b, 20 }, { 0x0c, 21 },
	{ 0x0d, 22 }, { 0x0e, 23 }, { 0x0f, 24 }, { 0x10, 25 },
	{ 0x11, 26 }, { 0x12, 27 }, { 0x13, 28 }, { 0x14, 29 },
	{ 0x15, 30 }, { 0x16, 31 }, { 0x17, 32 }, { 0x18, 33 },
	{ 0xFF, 00 }
};


static char readIOREGvalue(void)
{
	char value, param;
	int i;

	value = readPCFregister( PCF50606_IOREGC );
	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x001F;

	for ( i = 0 ; IOparvol[i].par != 0xFF ; i++ ) {
		if ( param == IOparvol[i].par ) {
			return IOparvol[i].vol;
		}
	}
	return 0;
}

static char readLPREGvalue(void)
{
	char value, param;
	int i;

	value = readPCFregister( PCF50606_LPREGC1 );
	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x001F;

	for ( i = 0 ; D123parvol[i].par != 0xFF ; i++ ) {
		if ( param == D123parvol[i].par ) {
			return D123parvol[i].vol;
		}
	}
	return 0;
}


static parvol_t DCDEparvol[] =
{
	{ 0x00,  9 }, { 0x01, 12 }, { 0x02, 15 }, { 0x03, 18 },
	{ 0x04, 21 }, { 0x05, 24 }, { 0x06, 27 }, { 0x07, 30 },
	{ 0x08, 33 }, { 0x09, 33 }, { 0x0a, 33 }, { 0x0b, 33 },
	{ 0x0c, 33 }, { 0x0d, 33 }, { 0x0e, 33 }, { 0x0f, 33 },
	{ 0xFF, 00 }
};

static char readDCDEvalue(void)
{
	char value, param;
	int i;

	value = readPCFregister( PCF50606_DCDEC1 );
	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x000F;

	for ( i = 0 ; DCDEparvol[i].par != 0xFF ; i++ ) {
		if ( param == DCDEparvol[i].par ) {
			return DCDEparvol[i].vol;
		}
	}
	return 0;
}


static parvol_t	DCDparvol[] =
{
	{ 0x00,  9 }, { 0x01,  9 }, { 0x02,  9 }, { 0x03,  9 },
	{ 0x04, 10 }, { 0x05, 10 }, { 0x06, 10 }, { 0x07, 10 },
	{ 0x08, 11 }, { 0x09, 11 }, { 0x0a, 11 }, { 0x0b, 11 },
	{ 0x0c, 12 }, { 0x0d, 12 }, { 0x0e, 12 }, { 0x0f, 12 },
	{ 0x10, 13 }, { 0x11, 13 }, { 0x12, 13 }, { 0x13, 13 },
	{ 0x14, 14 }, { 0x15, 14 }, { 0x16, 14 }, { 0x17, 14 },
	{ 0x18, 15 }, { 0x19, 18 }, { 0x1A, 21 }, { 0x1B, 24 },
	{ 0x1C, 27 }, { 0x1D, 30 }, { 0x1E, 33 }, { 0x1F, 36 },
	{ 0xFF, 00 }
};

static char readDCDvalue(void)
{ // TODO
	char value, param;
	int i;

	value = readPCFregister( PCF50606_DCDC4 );

	if ( value & 0x0080 ) {	// DCDC2
		value = readPCFregister( PCF50606_DCDC2 );
	} else {		// DCDC1
		value = readPCFregister( PCF50606_DCDC1 );
	}

	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x001F;

	for ( i = 0 ; DCDparvol[i].par != 0xFF ; i++ ) {
		if ( param == DCDparvol[i].par ) {
			return DCDparvol[i].vol ;
		}
	}

	return 0;
}

static void writeDCDvalue( char value )
{
	char temp;
	int i;

	for ( i = 0 ; DCDparvol[i].par != 0xFF ; i++ ) {
		if ( value == DCDparvol[i].vol ) {
			temp = readPCFregister( PCF50606_DCDC4 );
			if ( value & 0x0080 ) { // DCDC2
				writePCFregister( PCF50606_DCDC2, DCDparvol[i].par | PMIC_OPMOD7 );
			} else {
				writePCFregister( PCF50606_DCDC1, DCDparvol[i].par | PMIC_OPMOD7 );
			}
			return;
		}
	}
	return;
}

static parvol_t	DCUDparvol[] =
{
	{ 0x00,  9 }, { 0x01, 12 }, { 0x02, 15 }, { 0x03, 18 },
	{ 0x04, 21 }, { 0x05, 24 }, { 0x06, 27 }, { 0x07, 30 },
	{ 0x08, 33 }, { 0x09, 33 }, { 0x0a, 33 }, { 0x0b, 33 },
	{ 0x0c, 33 }, { 0x0d, 33 }, { 0x0e, 33 }, { 0x0f, 33 },
	{ 0x10, 40 }, { 0x11, 41 }, { 0x12, 42 }, { 0x13, 43 },
	{ 0x14, 44 }, { 0x15, 45 }, { 0x16, 46 }, { 0x17, 47 },
	{ 0x18, 48 }, { 0x19, 49 }, { 0x1A, 50 }, { 0x1B, 51 },
	{ 0x1C, 52 }, { 0x1D, 53 }, { 0x1E, 54 }, { 0x1F, 55 },
	{ 0xFF, 00 }
};

static char readDCUDvalue(void)
{
	char value, param;
	int i;

	value = readPCFregister( PCF50606_DCUDC1 );
	if (( value & 0x00E0 ) == 0x0 )
		return 0;

	param = value & 0x001F;

	for ( i = 0 ; DCUDparvol[i].par != 0xFF ; i++ ) {
		if ( param == DCUDparvol[i].par ) {
			return DCUDparvol[i].vol;
		}
	}
	return 0;
}

static void writeDCUDvalue(char value)
{
	int i;

	for ( i = 0 ; DCUDparvol[i].par != 0xFF ; i++ ) {
		if ( value == DCUDparvol[i].vol ) {
			writePCFregister( PCF50606_DCUDC1 , DCUDparvol[i].par | PMIC_OPMOD7 );
			return;
		}
	}
	// write 0 value , disable power controller
	writePCFregister( PCF50606_DCUDC1 , PMIC_OPMOD0 );
	return;
}

void pcf50606_IrqEnable (void)
{
	//volatile int *regT;

	//regT = (volatile int *)0x40e0000c;    //gpio0 is input
	GPDR0 &= ~(1 << 0);

	//regT = (volatile int *)0x40e00054;
	GAFR0_L &= ~((1 << 0) | (1 << 1)); //gpio0 is general gpio

	//regT = (volatile int *)0x40e0003c;  //enable GPIO0 falling edge detect
	GFER0 |= (1 << 0);

	//regT = (volatile int *)0x40d00004;  // ICMR ---enable GPIOx interrupt
	ICMR |= (1 << 8);
}


int pcf50606_init(void)
{
	char id;
	//int i;

	/*philps workaround for pcf5060x iic*/
	i2c_pcf5060x_workaround();

	udelay(1);
	if (_pcf50606_initialized == 1 ) return 0;

	pcf50606_IrqEnable();

	// enable clock: Power Manager I2C Unit ( Table 3-33 )
	// 0x4130:0004 |= bit15
	CKEN |= CKEN15_PI2C;

	// enable PWR_SDA, PWR_SCL pins: Power Manager I2C Enable
	// B_PWR_SDA and B_PWR_SCL pins in the schemetic.
	// 0x40f0_001C
	PCFR |= PCFR_PI2C_EN;

	// slave address to 0
	// PISR: Power Manager I2C Slave Address Register
	// 0x40F0_01A0
	PWISAR = 0x0;

	// control register to 0
	// PICR: Power Manager I2C Control Register
	// 0x40f0_0190
	PWICR |= (1 << 15);

	PWICR |= ICR_SCLE; 			// SCL enable
	PWICR |= ICR_IUE; 			// unit enable

	/* simon, see PMIC_init() in drivers/cpu/pmic/pcf50606.c of wPOST for P2. */
	writePCFregister( PCF50606_INT1M, 0xFF);
	writePCFregister( PCF50606_INT2M, 0xFF);
	writePCFregister( PCF50606_INT3M, 0xFF);

	/* ethan, enlarge the precharge current for low power battery */
	writePCFregister( PCF50606_MBCC3, 0x3A);

	/* writePCFregister( PCF50606_PWROKM, 0x44); */
	writePCFregister( PCF50606_PWROKM, 0xFF);
	writePCFregister( PCF50606_DCUDC1, PMIC_OPMOD4 | PMIC_REG_DCUD_50 );
	writePCFregister( PCF50606_D3REGC1, PMIC_OPMOD4 | PMIC_REG_LDO_25 );

//The following is added by Bill Chen 20060115
//0x23: IOREGC and 0x27: LPREGC1
	writePCFregister(0x23, PMIC_OPMOD7|0x15);
	writePCFregister(0x27, PMIC_OPMOD7|0X15);

//	writePCFregister(0x09, PMIC_OPMOD7|0x0f);
//

	/* Added by tium for lowering VLOWBAT threshold into 2.80v */
	writePCFregister( PCF50606_BVMC, 0x0E );
	/*power on sequence for BATT -> IO3V3*/
	writePCFregister( PCF50606_PSSC, 0x39 );

	writePCFregister(PCF50606_BBCC, 0x11);
	writePCFregister(PCF50606_LPREGC2,1);

	//readPCFregister (PCF50606_INT1);
	//readPCFregister (PCF50606_INT2);
	//readPCFregister( PCF50606_INT3 );
	// read ID
	id = readPCFregister( PCF50606_ID );
	if ( id != 0x92 ) 			// init fail
		return -1;

#ifdef DEBUG_PCF50606
//	printk("PCF50606: initialized, ID = 0x%x\n", id);
#endif
	_pcf50606_initialized = 1;
	return 0;
}


void pcf50606_dump_registers()
{
	char value;
	if ( pcf50606_init() != 0 ) {
#ifdef DEBUG_PCF50606
		printk( "PCF50606: initialization failure.\n" );
#endif
		return;
	}

	value = readD1REGvalue();
	value = readD2REGvalue();
	value = readD3REGvalue();
	value = readDCDvalue();
	value = readDCDEvalue();
	value = readDCUDvalue();
	value = readIOREGvalue();
	value = readLPREGvalue();

	char /*INT1, */INT2, INT3;

	//INT1 = readPCFregister (PCF50606_INT1);
	INT2 = readPCFregister (PCF50606_INT2);
	INT3 = readPCFregister ( PCF50606_INT3 );


#ifdef DEBUG_PCF50606
	printk( "D1REG:\t%d\n", value );
	printk( "D2REG:\t%d\n", value );
	printk( "D3REG:\t%d\n", value );
	printk( "DCD:\t%d\n", value );
	printk( "DCDE:\t%d\n", value );
	printk( "DCUD:\t%d\n", value );
	printk( "IOREG:\t%d\n", value );
	printk( "LPREG:\t%d\n", value );
	//printk( "INT1:\t0x%x\n", INT1);
	printk ( "INT2:\t0x%x\n", INT2);
	printk ( "INT3:\t0x%x\n", INT3);
#endif

}

void pcf50606_dump_pm_registers()
{
#ifdef DEBUG_PCF50606
	printk( "CKEN=\t%x\n", CKEN );
	printk( "PCFR=\t%x\n", PCFR );
	printk( "PWISAR=\t%x\n", PWISAR );
	printk( "PWICR=\t%x\n", PWICR );
	printk( "PWIDBR=\t%x\n", PWIDBR );
	printk( "PWISR=\t%x\n", PWISR );
#endif
}

void pcf50606_led2_on()
{
	writePCFregister(PCF50606_GPOC3, 0x0);
	writePCFregister(PCF50606_GPOC2, 0x0);
	return;

}

void pcf50606_pmu_set_voltage( unsigned char *regname, int value )
{
	if ( pcf50606_init() != 0 ) {
#ifdef DEBUG_PCF50606
		printk( "PCF50606: initialization failure.\n" );
#endif
		return;
	}

	if ( MyStrCmp( regname, "D1REG", 5 ) ) {
		writeD1REGvalue( (char) value );
#ifdef DEBUG_PCF50606
		printk( "D1REG:\t%d\n", readD1REGvalue() );
#endif
	} else if ( MyStrCmp( regname, "D2REG", 5 ) ) {
#ifdef DEBUG_PCF50606
		printk( "Not allowed to change voltage of %s\n", regname );
#endif
	} else if ( MyStrCmp( regname, "D3REG", 5 ) ) {
		writeD3REGvalue( (char) value );
#ifdef DEBUG_PCF50606
		printk( "D3REG:\t%d\n", readD3REGvalue() );
#endif
	} else if ( MyStrCmp( regname, "IOREG", 5 ) ) {
#ifdef DEBUG_PCF50606
		printk( "Not allowed to change voltage of %s\n", regname );
#endif
	} else if ( MyStrCmp( regname, "LPREG", 5 ) ) {
#ifdef DEBUG_PCF50606
		printk( "Not allowed to change voltage of %s\n", regname );
#endif
	} else if ( MyStrCmp( regname, "DCUD", 4 ) ) {
		writeDCUDvalue( (char) value );
#ifdef DEBUG_PCF50606
		printk( "DCUD:\t%d\n", readDCUDvalue() );
#endif
	} else if ( MyStrCmp( regname, "DCDE", 4 ) ) {
#ifdef DEBUG_PCF50606
		printk( "Not allowed to change voltage of %s\n", regname );
#endif
	} else if ( MyStrCmp( regname, "DCD", 3 ) ) {
		writeDCDvalue( (char) value );
#ifdef DEBUG_PCF50606
		printk( "DCD:\t%d\n", readDCDvalue() );
#endif
	} else {
#ifdef DEBUG_PCF50606
		printk( "Uexpected power supply name:%s\n", regname );
#endif
	}
}


/*void CHARGER_CharVoltLimitSet (u8 volt)
{
	u8 temp1;

	temp1 = readPCFregister( PCF50606_MBCC3 ) ;
	temp1 = (temp1 & 0xF0) | volt;
	writePCFregister( PCF50606_MBCC3, temp1 );

}*/

/*void _Charger_InterruptOn1 ( u8 int_ID)
{
	u8 temp1;

	temp1 = readPCFregister ( PCF50606_INT2M ) & ( ~int_ID) ;
	writePCFregister ( PCF50606_INT2M, temp1 );
}

void Charger_InterruptEnable (void)
{
	printk("\r\nEnable charger interrupt");

	_Charger_InterruptOn1( 0x01 );
	//_Charger_InterruptOn1( ChgInt_ID_Remove );
        //_Charger_InterruptOn1( ChgInt_ID_FastCharReady );
	// _Charger_InterruptOn1 ( 0x08 );
	//_Charger_InterruptOn1( ChgInt_ID_FastCharFinish );
        //_Charger_InterruptOn1( ChgInt_ID_Protection );
	// _Charger_InterruptOn1 ( 0x40 );
	// _Charger_InterruptOn1 ( 0x80 );

//}


void Charger_InterruptDisable ( void )
{
	//disable all charger interrupt
	writePCFregister ( PCF50606_INT2M, 0xFF );
	printk ("\r\nDisable all charger interrupt!");
}


void CHARGER_PreCurrRateSet (u8 CurRate)
{
	u8 temp1;

	temp1 = readPCFregister( PCF50606_MBCC3 ) ;
	temp1 = (temp1 & 0xCF) | CurRate;
	writePCFregister(PCF50606_MBCC3, temp1 );

	printk("\r\n0x2b=0x%x  ", readPCFregister(PCF50606_MBCC3 ) );

}


void CHARGER_WhachDogSet (u8 time)
{
	u8 temp1;

	temp1 = readPCFregister ( PCF50606_MBCC2 ) ;
	temp1 = (temp1 & 0x00) | time;
	writePCFregister ( PCF50606_MBCC2 , temp1 );

}

////void CHARGER_INIT (void)
////{
	//SetPMIC_UsePolling(PCF50606_MBCC1, 0xXX);
	//SetPMIC_UsePolling(PCF50606_MBCC2, 0xXX);
	// CHARGER_CharVoltLimitSet (0x0F);     //VCHGCON_500 is ok for charge to 4.2v
	// CHARGER_PreCurrRateSet (0x10);
	CHARGER_WhachDogSet (0x1E);     */

	//enable charger interrupt
	//_Charger_InterruptOn1( ChgInt_ID_Insert );
////	Charger_InterruptEnable();

////	printk ("\r\nPlease insert charger!");

////}



void pcf50606_interrupt_entry (void)
{
	printk("pcf50606_interrupt_entry----\n");
	GEDR0 |= (1 << 0);
	pcf50606_Interrupt_Processing();
}

char getOOCS()
{
    return readPCFregister (PCF50606_OOCS);
}

char getOOCC1()
{
    return readPCFregister (PCF50606_OOCC1);
}

void setOOCC2()
{
    writePCFregister (PCF50606_OOCC2,0x0f);
}

char getINT1()
{
    return readPCFregister (PCF50606_INT1);
}

void PCFWatchDogEnable(int IsEnable)
{
    char regData = readPCFregister(PCF50606_OOCC1);
    if (1 == IsEnable) {
        regData |= 0x08;
        writePCFregister(PCF50606_GPOC2, 0x05);
    }
    else {
        regData &= (~0x08);
        writePCFregister(PCF50606_GPOC2, 0x00);
    }
    writePCFregister(PCF50606_OOCC1, regData);
}

void PCFWatchDogReset()
{
    char regData = readPCFregister(PCF50606_OOCC1);
    regData |= 0x02;
    writePCFregister(PCF50606_OOCC1, regData);
}

void pcf_prepare_poweroff()
{
    writePCFregister(PCF50606_GPOC1, 0x07);//force led off
    writePCFregister(PCF50606_GPOC2, 0x00);//force keypad backlight off
    writePCFregister(PCF50606_GPOC3, 0x00);//force led off
    setOOCC2();//to press onkey 500ms longer start the machine
}

void ostdelay(int uSec);
void cli(void);
void pcf50606_power_off(void)
{
	writePCFregister( PCF50606_MBCC3, 0x3a );
	//Switch RED/BLUE led off
	pcf_prepare_poweroff();
	//lcd backlight off
	GAFR0_U &= ~(0x3);
	GPCR0 = 0x10000;
	ostdelay(5000);

	{
		writePCFregister(PCF50606_LPREGC2,0);
		ostdelay(3000);
		writePCFregister(PCF50606_OOCC1,readPCFregister(PCF50606_OOCC1)|0x1);
		//kprintf("power off now\n");
		//should not excute to here.
		cli();
		while(1);
	}
}

extern unsigned char usb_connecting_check;

void pcf50606_Interrupt_Processing()
{
	unsigned char INT2temp, INTMaskTemp;
	INT2temp = readPCFregister(PCF50606_INT2);
	INTMaskTemp = readPCFregister( PCF50606_INT2M );

	if((INT2temp & 0x01) && !(INTMaskTemp & 0x01))
	{
//The following is commented by Bill Chen
		if(GPLR1 & (0x1 << 9))
			{usb_connecting_check = 1;iimageupdate_by_usb=0;}
		else
			usb_connecting_check = 0;
		printk ("GPLR1:\t0x%x, usb_connecting_check=%d\n", GPLR1, usb_connecting_check);
	}

/* 	if( (INT2temp & 0x01) && !(INTMaskTemp & 0x01) )     //Bit[0] */
/* 	{ */
/* 		Print ("\r\nA valid charger is inserted!INTERRUPT"); */
/* 		//Disable charger insert INT;open charger remove INT  */
/* 		_Charger_InterruptOff1 (ChgInt_ID_Insert); */
/* 		_Charger_InterruptOn1 (ChgInt_ID_Remove); */
/* 		Print (" INT2M=0x%x\r\n", ReadPMIC_UsePolling ( PCF50606_INT2M ) ); */
/* 		CHARGER_TYPE_CHECK(); */
/* #ifdef AutoChg */
/* 		CHARGER_LowBat_CheckAndEnable(); */
/* 		 #endif */

/* 	} */
/* 	else  if (INT2temp & 0x01) */
/* 		Print ("A valid charger is inserted!status"); */


}
